import 'dart:io';
import 'dart:convert';
import 'package:dio/io.dart';
import 'package:dio/dio.dart';
import 'result_analyzed.dart';
// export 'result_analyzed.dart';
// export 'package:dio/src/form_data.dart';

/// `HttpManager` 类用于管理网络请求，封装了 Dio 实例和相关配置。
///
/// 这个类使用单例模式，确保整个应用中只有一个 `HttpManager` 实例。它封装了 Dio 网络库，并提供了一些静态方法和属性来配置和管理 HTTP 请求。
///
/// 主要功能:
/// - 配置和初始化 Dio 实例。
/// - 提供对请求参数、请求头、基础 URL 和取消请求的管理功能。
/// - 支持设置和清除授权信息。
enum HttpMethod { get, post}
typedef RequestResult = Future<ResponseAnalyzed>;
typedef ResponseObject = Map<String, dynamic>;
typedef Request = Map<String, dynamic>;


class HttpManager {
  // 私有构造函数，用于实现单例模式。
  HttpManager._privateConstructor();
  // 单例实例
  static final HttpManager instance = HttpManager._privateConstructor();
  // Dio 实例，用于发送 HTTP 请求
  final Dio _dio = Dio(BaseOptions(connectTimeout: const Duration(seconds: 60), receiveTimeout: const Duration(seconds: 60)));
  // 是否显示日志，默认为 false
  static bool showLog = false;
  // 基础的 URL，默认为空
  static String _baseUrl = "";
  // 基础的请求参数，默认为空
  static Request? _baseParam = {};
  // Dio 的配置选项
  static final _options = instance._dio.options;
  // 取消请求的令牌
  static final CancelToken _cancelToken = CancelToken();


  /// 设置基础 URL
  ///
  /// 将基础 URL 设置为 `newValue`。如果 URL 不以斜杠结尾，则会添加一个斜杠。
  ///
  /// 参数:
  /// - `newValue`: 新的基础 URL。
  static set baseUrl(String newValue) {
    _baseUrl = newValue;
    if (newValue.isNotEmpty) {
      _options.baseUrl = _baseUrl.endsWith("/") ? _baseUrl : "$_baseUrl/";
    }else {
      _options.baseUrl = _baseUrl;
    }
  }
  /// 获取当前的基础 URL
  static String get baseUrl => _options.baseUrl;

  /// 设置基础请求参数
  ///
  /// 这些参数将被添加到所有请求的查询参数中。
  ///
  /// 参数:
  /// - `param`: 类型为 `Request` 的请求参数。
  static setBaseParam(Request? param) => _baseParam = param;

  /// 设置请求头
  ///
  /// 这些头部信息将被添加到所有请求中。
  ///
  /// 参数:
  /// - `headers`: 类型为 `Request` 的请求头。
  static setHeaders(Request? headers) => _options.headers.addAll(headers!);
  /// 清除请求头
  static clearHeaders() => _options.headers.clear();




  /// 取消网络请求
  ///
  /// 取消指定的请求，如果没有指定请求，则取消所有请求。
  ///
  /// 参数:
  /// - `token`: 可选的取消令牌。
  static void cancel([CancelToken? token]) {
    if (token != null) token.cancel('cancel');
    _cancelToken.cancel('cancel');
  }

  /// 添加授权信息
  ///
  /// 将授权信息添加到请求头中。
  ///
  /// 参数:
  /// - `authorization`: 授权信息字符串。
  static setAuthorization(String authorization) => setHeaders({"Authorization": authorization});
  /// 清除授权信息
  static clearAuthorization() => setHeaders({"Authorization": null});

  // ====================== get 请求 =======================
  /// 静态方法，用于发送 GET 请求。
  ///
  /// 该方法将指定的 URL 和可选的查询参数传递给内部的 `_request` 方法，
  /// 以发送 GET 请求。请求完成后，返回服务器的响应。
  ///
  /// 参数:
  /// - `url`: 请求的 URL 地址，类型为 `String`。这是请求的目标地址。
  /// - `params`: 可选的请求参数，类型为 `Request`。这些参数将作为查询参数附加到 URL 中。
  /// - `cancelToken`: 可选的取消令牌，类型为 `CancelToken`，允许在必要时取消请求。
  ///
  /// 返回:
  /// - 返回一个 `Future<Response>`，表示服务器的响应结果。
  ///
  /// 方法详情:
  /// - 该方法是对 `_request` 方法的封装，指定了 `HttpMethod.get` 作为请求方法。
  /// - 方法通过将 `url`、`params` 和 `cancelToken` 传递给 `_request` 方法来执行实际的请求操作。
  /// - GET 请求通常用于从服务器获取数据，因此 `params` 参数会作为查询参数附加到 URL 中。
  ///
  /// 示例:
  /// ```dart
  /// Response response = await get(
  ///   'https://api.example.com/data',
  ///   params: {'key': 'value'}),
  /// );
  /// print(response.data);
  /// ```
  static Future<Response> get(String url, {Request? params, CancelToken? cancelToken}) async {
    return await _request(HttpMethod.get, url, params: params, cancelToken: cancelToken);
  }



  // ====================== get 请求 并解析 =======================
  /// 静态方法，用于发送 GET 请求，并对响应进行分析。
  ///
  /// 该方法会发送一个 GET 请求到指定的 URL，支持传递可选的查询参数和取消令牌。
  /// 请求完成后，响应会通过 `ResponseAnalyzed.analyzingAndCheckup` 方法进行分析，
  /// 并返回分析后的结果。
  ///
  /// 参数:
  /// - `url`: 请求的 URL 地址，类型为 `String`。
  /// - `params`: 可选的请求参数，类型为 `Request`。这些参数将作为查询参数传递。
  /// - `cancelToken`: 可选的取消令牌，类型为 `CancelToken`，允许在必要时取消请求。
  ///
  /// 返回:
  /// - 返回一个 `Future<ResponseAnalyzed>`，表示分析后的响应结果。
  ///
  /// 方法详情:
  /// - 方法首先调用 `get` 方法向指定的 URL 发送 GET 请求，并传递可选的查询参数和取消令牌。
  /// - 请求完成后，方法将返回的响应结果传递给 `ResponseAnalyzed.analyzingAndCheckup` 方法进行分析。
  /// - 分析结果将作为 `ResponseAnalyzed` 对象返回，供调用者进一步处理。
  ///
  /// 示例:
  /// ```dart
  /// ResponseAnalyzed result = await getAnalyzing(
  ///   'https://api.example.com/data',
  ///   params: {'key': 'value'}),
  /// );
  /// print(result.isSuccess);
  /// ```
  static Future<ResponseAnalyzed> getAnalyzing(String url, {Request? params, CancelToken? cancelToken}) async {
    var response = await get(url, params: params, cancelToken: cancelToken);
    return await ResponseAnalyzed.analyzingAndCheckup(response);
  }


  // ====================== post 请求 =======================
  /// 静态方法，用于发送 POST 请求。
  ///
  /// 该方法将指定的 URL 和可选的请求参数传递给内部的 `_request` 方法，
  /// 以发送 POST 请求。请求完成后，返回服务器的响应。
  ///
  /// 参数:
  /// - `url`: 请求的 URL 地址，类型为 `String`。
  /// - `params`: 可选的请求参数，类型为 `Request`。这些参数将作为请求体传递。
  /// - `cancelToken`: 可选的取消令牌，类型为 `CancelToken`，允许在必要时取消请求。
  ///
  /// 返回:
  /// - 返回一个 `Future<Response>`，表示服务器的响应结果。
  ///
  /// 方法详情:
  /// - 该方法是对 `_request` 方法的封装，指定了 `HttpMethod.post` 作为请求方法。
  /// - 方法通过将 `url`、`params` 和 `cancelToken` 传递给 `_request` 方法来执行实际的请求操作。
  /// - 由于 POST 请求通常用于提交数据，因此 `params` 参数会作为请求体数据传递给服务器。
  ///
  /// 示例:
  /// ```dart
  /// Response response = await post(
  ///   'https://api.example.com/submit',
  ///   params: {'key': 'value'}),
  /// );
  /// print(response.data);
  /// ```
  static Future<Response> post(String url, {Request? params, CancelToken? cancelToken}) async {
    return await _request(HttpMethod.post, url, params: params, cancelToken: cancelToken);
  }


  // ====================== post 请求 并解析 =======================
  /// 静态方法，用于发送 POST 请求，并对响应进行分析。
  ///
  /// 该方法会发送一个 POST 请求到指定的 URL，发送的请求参数是可选的。
  /// 请求完成后，响应会通过 `ResponseAnalyzed.analyzingAndCheckup` 方法进行分析，
  /// 并返回分析后的结果。
  ///
  /// 参数:
  /// - `url`: 请求的 URL 地址，类型为 `String`。
  /// - `params`: 可选的请求参数，类型为 `Request`。这些参数将作为请求体传递。
  /// - `cancelToken`: 可选的取消令牌，类型为 `CancelToken`，允许在必要时取消请求。
  ///
  /// 返回:
  /// - 返回一个 `Future<ResponseAnalyzed>`，表示分析后的响应结果。
  ///
  /// 方法详情:
  /// - 方法首先调用 `post` 方法向指定的 URL 发送 POST 请求，并传递可选的请求参数和取消令牌。
  /// - 请求完成后，方法将返回的响应结果传递给 `ResponseAnalyzed.analyzingAndCheckup` 方法进行分析。
  /// - 分析结果将作为 `ResponseAnalyzed` 对象返回，供调用者进一步处理。
  ///
  /// 示例:
  /// ```dart
  /// ResponseAnalyzed result = await postAnalyzing(
  ///   'https://api.example.com/submit',
  ///   params: {'key': 'value'}),
  /// );
  /// print(result.isSuccess);
  /// ```
  static Future<ResponseAnalyzed> postAnalyzing(String url, {Request? params, CancelToken? cancelToken}) async {
    var response = await post(url, params: params, cancelToken: cancelToken);
    return await ResponseAnalyzed.analyzingAndCheckup(response);
  }

  /// 静态方法，重新发起请求，用于使用给定的 `RequestOptions` 重试 HTTP 请求。
  ///
  /// 该方法会使用 Dio 的 `fetch` 方法重新发送请求，并记录请求的开始时间和结束时间。
  /// 请求完成后，会分析响应并返回分析结果。如果请求过程中发生异常，会捕获并处理该异常，
  /// 并记录相关日志。
  ///
  /// 参数:
  /// - `requestOptions`: 类型为 `RequestOptions`，表示要重试的请求选项。包含了请求的 URL、方法、
  ///   请求体数据等信息。
  ///
  /// 返回:
  /// - 返回一个 `Future<ResponseAnalyzed>`，表示分析后的响应结果。
  ///
  /// 方法详情:
  /// - `url` 是从 `requestOptions.uri` 提取的完整 URL 字符串，用于日志记录。
  /// - `method` 是请求的 HTTP 方法，通过 `requestOptions.method` 获取。
  /// - 方法首先记录请求的开始时间 `startTime`，然后使用 Dio 的 `fetch` 方法重新发送请求。
  /// - 如果请求成功，方法将记录结束时间 `endTime`，并调用 `_log` 方法记录请求日志。
  /// - 成功的响应会传递给 `ResponseAnalyzed.analyzingAndCheckup` 进行分析，
  ///   并返回分析后的结果。
  /// - 如果请求过程中发生 `DioException` 异常，方法会捕获异常并处理，
  ///   记录结束时间 `endTime` 和相关日志，并将处理后的响应传递给 `ResponseAnalyzed.analyzingAndCheckup` 进行分析。
  ///
  /// 示例:
  /// ```dart
  /// RequestOptions options = RequestOptions(
  ///   path: 'https://api.example.com/data',
  ///   method: 'GET',
  ///   data: {'key': 'value'},
  /// );
  /// ResponseAnalyzed result = await retryRequestWithFetch(options);
  /// print(result.isSuccess);
  /// ```
  static Future<ResponseAnalyzed> retryRequestWithFetch(RequestOptions requestOptions) async {
    // 从 RequestOptions 中提取 URL 和 HTTP 方法
    String url = requestOptions.uri.toString();
    String method = requestOptions.method;
    final startTime = DateTime.now().toString();
    try {
      // 使用 Dio 的 fetch 方法重新发送请求
      final response = await HttpManager.instance._dio.fetch(requestOptions);
      final endTime = DateTime.now().toString();
      // 记录成功请求的日志
      _log(url, method, requestOptions.data, null, startTime, endTime, response);
      // 分析响应并返回结果
      return await ResponseAnalyzed.analyzingAndCheckup(response);
    } on DioException catch (e) {
      // 处理异常并记录日志
      final endTime = DateTime.now().toString();
      Response? response = _dioError(e);
      _log(url, method, requestOptions.data, null, startTime, endTime, response);
      // 分析异常响应并返回结果
      return await ResponseAnalyzed.analyzingAndCheckup(response);
    }
  }


  // ================== 设置代理(安装客户端适配器) ================
  /// 静态方法，用于为 HTTP 请求设置代理服务器。
  ///
  /// 该方法通过配置 `Dio` 的 `httpClientAdapter` 来设置代理服务器。
  /// 当代理服务器的主机和端口被指定时，所有通过 `Dio` 发送的 HTTP 请求
  /// 都将通过该代理服务器进行转发。
  ///
  /// 参数:
  /// - `host`: 代理服务器的主机地址，默认为空字符串。如果为空字符串，则不会设置代理。
  /// - `port`: 代理服务器的端口号，默认为空字符串。如果为空字符串，则不会设置代理。
  ///
  /// 详情:
  /// - `createHttpClient`: 通过创建自定义的 `HttpClient` 实例来配置代理服务器。
  /// - `badCertificateCallback`: 允许接受不受信任的证书，通常用于开发环境中跳过 SSL 验证。
  /// - `findProxy`: 根据 `host` 和 `port` 参数设置代理服务器的地址。
  ///   如果 `host` 和 `port` 都不为空，则设置代理；否则，不启用代理。
  ///
  /// 注意:
  /// - 代理服务器会在当前设备上生效，即在你正在运行应用的设备上生效，
  ///   而不是在宿主平台（如 iOS 或 Android 模拟器）生效。
  ///
  /// 示例:
  /// ```dart
  /// // 设置代理服务器为 localhost:8888
  /// HttpManager.setProxy(host: "localhost", port: "8888");
  /// ```
  static setProxy({String? host = "", String? port = ""}) {
    HttpManager.instance._dio.httpClientAdapter = IOHttpClientAdapter(
      createHttpClient: () {
        final client = HttpClient();

        // 允许所有证书（包括不受信任的证书），用于开发环境
        client.badCertificateCallback = (cert, host, port) {
          return true; // 信任证书
        };

        // 如果 host 和 port 都不为空，设置代理
        if (host!.isNotEmpty && port!.isNotEmpty) {
          client.findProxy = (uri) {
            // 将请求代理至指定的 host 和 port
            return "PROXY $host:$port"; // 设置代理地址
          };
        }

        return client;
      },
    );
  }



  /// 私有的静态方法，用于发送 HTTP 请求，并处理请求日志和异常。
  ///
  /// 该方法根据指定的 HTTP 方法和 URL 发送请求，支持传递查询参数和取消令牌。
  /// 请求过程会记录开始时间和结束时间，并在请求成功或失败后记录日志信息。
  ///
  /// 参数:
  /// - `method`: 请求的 HTTP 方法，类型为 `HttpMethod`。支持 GET、POST 等请求方法。
  /// - `url`: 请求的 URL 地址，类型为 `String`。
  /// - `params`: 可选的请求参数，类型为 `Request`。这些参数将作为查询参数或请求体传递，
  ///   具体取决于 HTTP 方法。如果没有提供，则默认为空的 `Map`。
  /// - `cancelToken`: 可选的取消令牌，类型为 `CancelToken`，允许在必要时取消请求。
  ///
  /// 返回:
  /// - 返回一个 `Future<Response>`，表示服务器的响应结果。
  ///
  /// 方法详情:
  /// - `params2` 是一个用于存储最终请求参数的 `Map` 对象，它将传入的 `params`
  ///   和 `_baseParam` 合并后作为最终的查询参数或请求体。
  /// - `httpMethod` 通过从 `HttpMethod` 枚举中提取方法名称来确定当前请求的 HTTP 方法类型。
  /// - 方法在请求之前记录开始时间，并在请求完成后记录结束时间。
  /// - 请求通过 `_sendRequest` 方法发送，处理完成后，将响应对象返回。
  /// - 在捕获到 `DioException` 时，方法通过 `_dioError` 处理异常，并返回处理后的响应对象。
  /// - 无论请求成功与否，方法都会调用 `_log` 方法记录详细的请求和响应信息，
  ///   包括 URL、HTTP 方法、参数、时间戳和响应内容。
  ///
  /// 示例:
  /// ```dart
  /// Response response = await _request(
  ///   HttpMethod.post,
  ///   'https://api.example.com/submit',
  ///   params: {'key': 'value'}),
  /// );
  /// print(response.data);
  /// ```
  static Future<Response> _request(HttpMethod method, String url, {Request? params, CancelToken? cancelToken}) async {
    // 合并传入的请求参数和基础参数
    Map<String, dynamic>? params2 = {};
    params2.addAll(params ?? {});
    if (_baseParam != null) params2.addAll(_baseParam!);
    // 提取 HTTP 方法的名称
    var httpMethod = method.toString().substring(11, method.toString().length);
    final startTime = DateTime.now().toString();
    try {
      // 发送请求并获取响应
      Response response = await _sendRequest(method, url, params2, cancelToken);
      final endTime = DateTime.now().toString();
      // 记录请求日志
      _log(url, httpMethod, params2, null, startTime, endTime, response);
      return response;
    } on DioException catch (e) {
      // 处理异常并记录日志
      final endTime = DateTime.now().toString();
      Response? response = _dioError(e);
      _log(url, httpMethod, params2, null, startTime, endTime, response);
      return response;
    }
  }

  /// 静态方法，用于上传文件或表单数据到指定的 URL。
  ///
  /// 这个方法通过 `Dio` 库发送 POST 请求，将 `FormData` 数据上传到服务器。
  /// 该方法还支持附加查询参数、监控上传进度，以及捕获和处理网络异常。
  ///
  /// 参数:
  /// - `url`: 目标上传的 URL 地址。
  /// - `params`: 可选的请求参数，类型为 `Request`，将作为查询参数附加到 URL 中。
  /// - `formData`: 要上传的表单数据，类型为 `FormData`，用于传递文件和其他表单字段。
  /// - `onSendProgress`: 可选的上传进度回调函数，类型为 `ProgressCallback`，
  ///   通过 `(int sent, int total)` 参数提供上传的进度信息。
  /// - `cancelToken`: 可选的取消令牌，类型为 `CancelToken`，允许在必要时取消上传操作。
  ///
  /// 返回:
  /// - 返回一个 `Future<Response>`，表示服务器的响应结果。
  ///
  /// 异常:
  /// - 在发生 `DioException` 时捕获异常，并通过 `_dioError` 方法处理，将其转换为标准的响应对象。
  ///
  /// 方法详情:
  /// - 在上传过程中，方法会记录请求的开始时间和结束时间，用于日志记录。
  /// - 所有请求参数会被合并到一个 `Map` 对象 `params2` 中，其中包括传入的 `params` 以及 `_baseParam`。
  /// - 请求完成后，无论成功或失败，都会调用 `_log` 方法记录请求的详细信息，包括 URL、HTTP 方法、参数、开始和结束时间，以及响应内容。
  ///
  /// 示例:
  /// ```dart
  /// FormData formData = FormData.fromMap({
  ///   "name": "file",
  ///   "file": await MultipartFile.fromFile("path/to/file"),
  /// });
  /// Response response = await upload(
  ///   'https://example.com/upload',
  ///   null,
  ///   formData,
  ///   onSendProgress: (int sent, int total) {
  ///     print('已上传: $sent, 总共: $total');
  ///   },
  ///   cancelToken: CancelToken(),
  /// );
  /// print(response.data);
  /// ```
  static Future<Response> upload(String url, Request? params, FormData formData, {ProgressCallback? onSendProgress, CancelToken? cancelToken}) async {
    Dio dio = HttpManager.instance._dio;
    Map<String, dynamic>? params2 = {};
    params2.addAll(params ?? {});
    if (_baseParam != null) { params2.addAll(_baseParam!); }
    var httpMethod = HttpMethod.post;
    final startTime = DateTime.now().toString();
    try {
      Response? response = await dio.post(
        url,
        data: formData,
        queryParameters: params2,
        onSendProgress: onSendProgress,
        options: Options(contentType: Headers.jsonContentType),
      );
      final endTime = DateTime.now().toString();
      _log(url, httpMethod, params2, formData, startTime, endTime, response);
      return response;
    } on DioException catch (e) {
      final endTime = DateTime.now().toString();
      Response? response = _dioError(e);
      _log(url, httpMethod, params2, formData, startTime, endTime, response);
      return response;
    }
  }

  /// 上传数据，并解析
  /// 静态方法，用于上传文件或表单数据到指定的 URL。
  ///
  /// 这个方法通过 `upload` 发送 POST 请求，将 `FormData` 数据上传到服务器。
  static Future<ResponseAnalyzed> uploadAnalyzing(
      HttpMethod method, String url, Request? params, FormData formData, {CancelToken? cancelToken}) async {
    var response = await upload(url, params, formData, cancelToken: cancelToken);
    ResponseAnalyzed result = await ResponseAnalyzed.analyzingAndCheckup(response);
    return result;
  }
  /// 静态方法，用于将流数据上传到指定的 URL。
  ///
  /// 这个方法通过 `Dio` 库发送 POST 请求，将 `Stream` 数据上传到服务器。
  /// 可以在上传过程中通过 `onSendProgress` 回调获取上传进度，并可以通过 `cancelToken`
  /// 取消上传操作。
  ///
  /// 注意：使用此方法时，需要确保 `Stream` 包含已知长度的数据，并在 `headers` 中设置
  /// `Content-Length`。
  ///
  /// 参数:
  /// - `url`: 目标上传的 URL 地址。
  /// - `stream`: 要上传的数据流，通常用于上传大文件或流式数据。
  /// - `onSendProgress`: 可选的上传进度回调函数，类型为 `ProgressCallback`，
  ///   通过 `(int sent, int total)` 参数提供上传的进度信息。
  /// - `cancelToken`: 可选的取消令牌，类型为 `CancelToken`，允许在必要时取消上传操作。
  ///
  /// 返回:
  /// - 返回一个 `Future<void>`，表示上传操作的完成情况。
  ///
  /// 异常:
  /// - 如果上传失败或者过程中出现问题，会抛出相应的异常。
  ///
  /// 示例:
  /// ```dart
  /// Stream<List<int>> fileStream = File('path/to/file').openRead();
  /// await uploadStream('https://example.com/upload', fileStream,
  ///   onSendProgress: (int sent, int total) {
  ///     print('已上传: $sent, 总共: $total');
  ///   },
  ///   cancelToken: CancelToken(),
  /// );
  /// ```
  static Future uploadStream(String url, Stream stream, {ProgressCallback? onSendProgress, CancelToken? cancelToken}) async {
    Dio dio = HttpManager.instance._dio;
    await dio.post(
      url,
      data: stream,
      options: Options(headers: {Headers.contentLengthHeader: stream.length}),
      onSendProgress: onSendProgress,
      cancelToken: cancelToken,
    );
  }

  /// 下载文件
  /// 静态方法，用于下载文件并保存到指定路径。
  ///
  /// 该方法会将指定的 URL 指向的文件下载到本地，并将其保存到 `savePath` 路径下，
  /// 文件名为 `fileName`。可以选择传递一个进度回调函数 `onReceiveProgress`，
  /// 以便在下载过程中跟踪下载进度。如果发生异常，会捕获并处理异常，
  /// 并记录相关日志。
  ///
  /// 参数:
  /// - `url`: 要下载的文件的 URL 地址，类型为 `String`。如有中文，请进行编码处理 String encodedUrl = Uri.encodeFull(url);
  /// - `savePath`: 文件保存的路径，类型为 `String`。文件将被保存到这个路径下。
  /// - `fileName`: 保存的文件名，类型为 `String`。文件将以这个名称保存。
  /// - `onReceiveProgress`: 可选的进度回调函数，类型为 `ProgressCallback`，
  ///   用于跟踪下载进度。回调函数接受两个参数：已接收的字节数和总字节数。
  /// - `cancelToken`: 可选的取消令牌，类型为 `CancelToken`，允许在必要时取消下载请求。
  ///
  /// 返回:
  /// - 返回一个 `Future<Response>`，表示下载操作的响应结果。
  ///
  /// 方法详情:
  /// - 方法首先初始化请求的参数 `params2` 和 `httpMethod`，并记录请求的开始时间 `startTime`。
  /// - 使用 Dio 的 `download` 方法下载文件，文件将被保存到指定的路径和文件名。
  /// - 如果提供了 `onReceiveProgress` 回调函数，会在下载过程中调用该函数以报告进度。
  /// - 请求完成后，方法将记录结束时间 `endTime` 并调用 `_log` 方法记录下载日志。
  /// - 如果下载过程中发生 `DioException` 异常，方法会捕获异常，记录相关日志，并返回处理后的响应。
  ///
  /// 示例:
  /// ```dart
  /// await downloadFile(
  ///   'https://example.com/file.zip',
  ///   '/path/to/save',
  ///   'file.zip',
  ///   onReceiveProgress: (received, total) {
  ///     print('Received $received of $total');
  ///   },
  /// );
  /// ```
  static Future<Response> downloadFile(String url, String savePath, String fileName, {ProgressCallback? onReceiveProgress, CancelToken? cancelToken}) async {
    Dio dio = HttpManager.instance._dio;
    Map<String, dynamic>? params2 = {};
    Request? params;
    params2.addAll(params ?? {});
    if (_baseParam != null) { params2.addAll(_baseParam!); }
    HttpMethod method = HttpMethod.get;
    var httpMethod = method.toString().substring(11, method.toString().length);
    final startTime = DateTime.now().toString();
    try {
      // 使用 Dio 的 download 方法下载文件
      Response response = await dio.download(
        url,
        "$savePath/$fileName",
        cancelToken: cancelToken,
        onReceiveProgress: (received, total) {
          if (onReceiveProgress != null) onReceiveProgress(received, total);
        },
      );
      // 记录下载日志
      final endTime = DateTime.now().toString();
      _log(url, httpMethod, params2, "download", startTime, endTime, response, savePath: savePath);
      return response;
    } on DioException catch (e) {
      // 处理异常并记录日志
      final endTime = DateTime.now().toString();
      Response? response = _dioError(e);
      _log(url, httpMethod, params2, "download", startTime, endTime, response, savePath: savePath);
      return response;
    }
  }



  /// 静态方法，用于发送 HTTP 请求。
  ///
  /// 根据指定的请求方法（GET 或 POST）向指定的 URL 发送请求。方法会根据请求类型选择合适的请求方式，
  /// 并传递相关的参数。请求完成后，返回服务器的响应。若请求过程中出现异常，则会处理异常并返回错误信息。
  ///
  /// 参数:
  /// - `method`: 请求的方法类型，类型为 `HttpMethod`。支持 `HttpMethod.get` 和 `HttpMethod.post`。
  /// - `url`: 请求的 URL 地址，类型为 `String`。这是请求的目标地址。
  /// - `params`: 可选的请求参数，类型为 `Request`。
  ///   - 对于 GET 请求，这些参数会作为查询参数附加到 URL 中。
  ///   - 对于 POST 请求，这些参数会作为请求体数据发送。
  /// - `cancelToken`: 可选的取消令牌，类型为 `CancelToken`，允许在必要时取消请求。
  ///
  /// 返回:
  /// - 返回一个 `Future<Response>`，表示服务器的响应结果。如果发生异常，则返回处理后的错误响应。
  ///
  /// 方法详情:
  /// - 方法首先获取 `Dio` 实例，然后根据 `method` 参数决定使用 GET 还是 POST 请求方式。
  /// - 对于 GET 请求，`params` 参数作为查询参数传递；对于 POST 请求，`params` 参数经过 JSON 编码后作为请求体数据传递。
  /// - 使用 `Options` 设置请求的 `Content-Type` 为 `application/json`。
  /// - 若请求过程中发生 `DioException` 异常，会调用 `_dioError` 方法处理异常，并返回处理后的响应。
  ///
  /// 示例:
  /// ```dart
  /// Response response = await _sendRequest(
  ///   HttpMethod.get,
  ///   'https://api.example.com/data',
  ///   params: Request(query: {'key': 'value'}),
  /// );
  /// print(response.data);
  /// ```
  ///
  /// ```dart
  /// Response response = await _sendRequest(
  ///   HttpMethod.post,
  ///   'https://api.example.com/submit',
  ///   params: Request(body: {'key': 'value'}),
  /// );
  /// print(response.data);
  /// ```
  static Future<Response> _sendRequest(HttpMethod method, String url, Request? params, CancelToken? cancelToken) async {
    Dio dio = HttpManager.instance._dio;
    try {
      switch (method) {
        case HttpMethod.get:
        // 发送 GET 请求，参数作为查询参数附加到 URL
          return await dio.get(url, queryParameters: params, options: Options(contentType: Headers.jsonContentType), cancelToken: cancelToken);
        case HttpMethod.post:
          // 发送 POST 请求，参数经过 JSON 编码后作为请求体数据
          return await dio.post(url, data: jsonEncode(params), options: Options(contentType: Headers.jsonContentType), cancelToken: cancelToken);
        default:
          throw Exception("请求方式错误");
      }
    } on DioException catch (e) {
      // 处理 Dio 异常并返回处理后的响应
      return _dioError(e);
    }
  }

  /// 处理错误信息
  static Response _dioError(DioException error) {
    Response? response = error.response;
    if (response != null) {
      if (response.data is Map) {
        Map data = error.response?.data;
        if (data.containsKey("code")) {
          response.data["code"] = data["code"];
        }
        if (data.containsKey("message")) {
          response.data["data"] = data["message"];
        }
      } else if (response.statusCode != null || response.statusMessage != null || response.data == null) {
        response.data = {"code": response.statusCode, "message": response.statusMessage, "data": response.data};
      }
    } else {
      response = Response(requestOptions: RequestOptions(data: error.requestOptions), data: {});
      switch (error.type) {
        case DioExceptionType.connectionTimeout:
          response.data = {"code": 500, "message": '连接超时', "data": ""};
        case DioExceptionType.sendTimeout:
          response.data = {"code": 400, "message": '发送超时', "data": ""};
        case DioExceptionType.receiveTimeout:
          response.data = {"code": 500, "message": '响应超时', "data": ""};
        case DioExceptionType.badResponse:
          response.data = {"code": 404, "message": '请求地址不存在', "data": ""};
        case DioExceptionType.cancel:
          response.data = {"code": 400, "message": '请求取消', "data": ""};
        case DioExceptionType.unknown:
          response.data = {"code": 400, "message": '未知错误,请检查网络或服务器', "data": ""};
        default:
          response.data = {"code": 400, "message": '未知错误,请检查网络或服务器', "data": ""};
      }
    }
    return response;
  }


  static _log(url, httpMethod, params2, formData, startTime, endTime, response, {String? savePath}) {
    if (showLog == true) {
      final baseUrl = HttpManager.instance._dio.options.baseUrl;
      final userToken = HttpManager.instance._dio.options.headers["UserToken"];
      if (formData == null) {
        debugLogger("""\n
============================================================================================================

请求地址：$baseUrl${url.replaceFirst("/", "")}
请求方式：$httpMethod
请求令牌：$userToken
开始请求：$startTime
请求结束：$endTime
请求参数：$params2
响应数据：$response

============================================================================================================

        """);
      }else if (formData == "download") {
        debugLogger("""\n
============================================================================================================

请求地址：$baseUrl${url.replaceFirst("/", "")}
请求方式：$httpMethod
请求令牌：$userToken
开始下载：$startTime
下载结束：$endTime
请求参数：$params2
响应数据：$response
下载结果：${response.statusCode} ${response.statusMessage}
保存路径：$savePath

============================================================================================================
        """);
      }else {
        debugLogger("""\n
============================================================================================================

请求地址：$baseUrl${url.replaceFirst("/", "")}
请求方式：$httpMethod
请求令牌：$userToken
开始上传：$startTime
上传结束：$endTime
请求表单：$formData
请求参数：$params2
响应数据：$response

============================================================================================================
        """);
      }
    }
  }
}
